package com.example.sql.visitor;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Queue;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLInSubQueryExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectJoin;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
import com.alibaba.druid.util.StringUtils;
import com.example.sql.util.StrUtil;
import com.example.sql.vo.TableInfo;
import com.example.sql.vo.UpdateJoinTable;
import com.example.sql.vo.UpdateWhere;
import com.example.sql.vo.WhereWrapper;

public class OracleSelectVisitor extends OracleASTVisitorAdapter {

    @Override
    public boolean visit(OracleSelectJoin firstJoin) {

        if (firstJoin.getParent() instanceof OracleSelectQueryBlock from) {
            List<TableInfo> tableInfoList = getTableInfoList(firstJoin, new ArrayList<>());
            Optional<TableInfo> isTarget = tableInfoList.stream().filter(table -> table.contains("t2")).findAny();
            // 判断目标表是否存在
            if (isTarget.isPresent()) {

                UpdateJoinTable updateJoinTable = new UpdateJoinTable(firstJoin, from);
        
                updateJoinTable.doUpdate();
            }

        }

        return true;
    }


    @Override
    public boolean visit(SQLBinaryOpExpr x) {
        // 在此阶段判断上一个节点是什么 并进行各种判断
        SQLObject parent = x.getParent();
        Queue<WhereWrapper> whereQueue = new ArrayDeque<>();
        Queue<UpdateWhere> afterUpdateWhereQueue = new ArrayDeque<>();

        // on块
        if (parent instanceof SQLJoinTableSource join) {
            // 拼接要加入的条件
            List<TableInfo> tableInfoList = getTableInfoList(join, new ArrayList<>());
            filterCustomColumnTable(x, tableInfoList, whereQueue, afterUpdateWhereQueue);

            return false;
        }

        // where块
        if (parent instanceof OracleSelectQueryBlock where) {
            // 获取表信息时忽略右表
            List<TableInfo> tableInfoList = getTableInfoList(where.getFrom(), new ArrayList<>(), Boolean.FALSE);
            filterCustomColumnTable(x, tableInfoList, whereQueue, afterUpdateWhereQueue);

            if (!afterUpdateWhereQueue.isEmpty()) {
                while (afterUpdateWhereQueue.peek() != null) {
                    afterUpdateWhereQueue.poll().doUpdate();
                }
            }

            return false;
        }

        return false;
    }



    /**
     * 遍历并获得当前层级下的表别名
     *
     * @param tableSource   表信息 由form块获取
     * @param tableInfoList 用于迭代的表信息集合
     * @return 表信息集合
     */
    protected List<TableInfo> getTableInfoList(SQLTableSource tableSource, List<TableInfo> tableInfoList) {
        return getTableInfoList(tableSource, tableInfoList, Boolean.TRUE);
    }

    /**
     * 遍历并获得当前层级下的表别名
     *
     * @param tableSource   表信息 由form块获取
     * @param tableInfoList 用于迭代的表信息集合
     * @param isGetRight    关联查询是是否获取右表信息
     * @return 表信息集合
     */
    private List<TableInfo> getTableInfoList(SQLTableSource tableSource, List<TableInfo> tableInfoList, Boolean isGetRight) {
        if (tableSource instanceof SQLSubqueryTableSource) { // OracleSelectSubqueryTableSource
            tableInfoList.add(new TableInfo("TODO", tableSource.getAlias()));
        }

        if (tableSource instanceof SQLJoinTableSource joinSource) {
            getTableInfoList(joinSource.getLeft(), tableInfoList, isGetRight);
            // 这里如果是join语句在where条件中是不需要加入右表的 因为关联查询关联表不应该影响数据条数 应该只影响关联结果
            if (isGetRight) {
                getTableInfoList(joinSource.getRight(), tableInfoList, true);
            }
        }

        if (tableSource instanceof SQLExprTableSource) {
            tableInfoList.add(new TableInfo(String.valueOf(tableSource), tableSource.getAlias()));
        }
        return tableInfoList;
    }

    /**
     * 过滤已经自定义了字段的表信息, 例如当前条件中已经追加了 is_delete is false 则不需要再在语句中加入 is_delete is true
     *
     * @param where         条件
     * @param tableInfoList 表信息
     */
    private void filterCustomColumnTable(SQLExpr where, List<TableInfo> tableInfoList, Queue<WhereWrapper> whereQueue, Queue<UpdateWhere> afterUpdateWhereQueue) {
        if (Objects.isNull(where)) {
            return;
        }

        // 遍历左右两端
        SQLExpr sqlExpr = where;
        if (sqlExpr instanceof SQLBinaryOpExpr binOpExpr && Objects.nonNull(sqlExpr = binOpExpr.getLeft())) { // while
            filterCustomColumnTable(sqlExpr, tableInfoList, whereQueue, afterUpdateWhereQueue);
        }

        sqlExpr = where;
        if (sqlExpr instanceof SQLBinaryOpExpr binOpExpr && Objects.nonNull(sqlExpr = binOpExpr.getRight())) { // while
            filterCustomColumnTable(sqlExpr, tableInfoList, whereQueue, afterUpdateWhereQueue);
        }

        // 未设置别名 则直接判断是否当前字段
        if (where instanceof SQLInSubQueryExpr subQueryExpr) {
            filterCustomColumnTable(subQueryExpr.getExpr(), tableInfoList, whereQueue, afterUpdateWhereQueue);
        }

        // 处理形如 A = 1 存在字段名相同的条件则去掉
        if (where instanceof SQLIdentifierExpr identifierExpr) {
            UpdateWhere.addQueue(whereQueue, identifierExpr);
            UpdateWhere.pollQueue(whereQueue, afterUpdateWhereQueue);
            return;
            
            // tableInfoList.removeIf(item -> Objects.isNull(item.getAlias()) && Objects.equals(ColumnName, ((SQLIdentifierExpr) where).getName()));
        }

        // 处理形如 a.A = 1 存在别名和字段名都相同的条件则去掉
        if (where instanceof SQLPropertyExpr propertyExpr) {
            UpdateWhere.addQueue(whereQueue, propertyExpr);
            UpdateWhere.pollQueue(whereQueue, afterUpdateWhereQueue);
            return;

            // tableInfoList.removeIf(
            //         item -> StringUtils.equalsIgnoreCase(propertyExpr.getOwner().toString(), StrUtil.blankToDefault(item.getAlias(), item.getTableName()))
            //                 && StringUtils.equalsIgnoreCase(propertyExpr.getName(), ColumnName));
        }

        // 处理形如 A = 1 存在字段名相同的条件则去掉
        if (where instanceof SQLCharExpr) {
            // System.out.println(" value = " + where);
            return;
        }
    }



}
